package yourobot.robots;
import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;

import yourobot.Level;
import yourobot.bonus.Bonus;
import yourobot.config.ColorConfig;
import yourobot.config.KeyConfig;
import fr.umlv.zen.KeyboardEvent;
/**
 * 
 * @author mehdimasrour
 *
 */
public class Player {
	private final LinkedList<KeyboardEvent> keylist;
	private float life;
	private final Body corps;
	private final KeyConfig config;
	private final int id;
	private double angle;
	private final ColorConfig color;
	private Bonus bonus;
	private final World w;
	
	private final static int DEFAULT_LIFE = 100;
	public final static int DEFAULT_RADIUS = 25;
	private final static int DEFAULT_ANGLE = 30;
	
	/**
	 * 
	 * @param p : id of the player ( should be 1 or 2 ... )
	 * @param w : The world in which the player will be placed
	 * @param start : Vec2 corresponding to the starting area
	 */
	public Player(int p, World w, Vec2 start){
		this(p,DEFAULT_LIFE,w,start);
	}
	
	/**
	 * 
	 * @param np : id of the player ( should be 1 or 2 ... )
	 * @param life : Number of Health Point given to the player at the beggining
	 * @param w : The world in which the player will be placed
	 * @param start : Vec2 corresponding to the starting area
	 * 
	 */
	public Player(int np, int life, World w, Vec2 start){
		this.life = life;
		this.id = np;
		this.w = w;
		angle = 0;
		bonus = null;
		keylist = new LinkedList<>();
		config = new KeyConfig(np);
		color = new ColorConfig(np);
		
		BodyDef bd = new BodyDef();
		bd.type = BodyType.DYNAMIC;
		bd.position.set(start.x, start.y+(np-1)*18);
		corps = w.createBody(bd);
		CircleShape c = new CircleShape();
		c.m_radius = DEFAULT_RADIUS;
		FixtureDef fd = new FixtureDef();
		fd.shape = c;
		fd.restitution = 0.1f;
		fd.userData = "player";
		corps.setUserData(this);
		corps.createFixture(fd);
		corps.setLinearDamping(0.2f);
	}

	/**
	 * 
	 * @return The color of the player
	 */
	public Color getColor(){
		return color.getColor();
	}
	
	/**
	 * 
	 * @param k : KeyboardEvent to add to the list
	 */
	public void addKey(KeyboardEvent k){
		keylist.add(k);
	}
	
	/**
	 * 
	 * @return Current health points of the player
	 */
	public float getLife(){
		return life;
	}
	
	/**
	 * 
	 * @return If the player is dead or not
	 */
	public boolean isDead(){
		return Math.floor(life)<=0;
	}
	
	/**
	 * 
	 * @return The id of the player (1 or 2 atm)
	 */
	public int getId(){
		return id;
	}
	
	/**
	 * 
	 * @return The Vec2 corresponding to the player's position
	 */
	public Vec2 getPosition(){
		return corps.getPosition();
	}
	
	/**
	 * 
	 * @return The angle of the player
	 */
	public double getAngle(){
		return angle;
	}
	
	/**
	 * 
	 * @param l : Level to be checked
	 * @return true if the player has finished the level
	 */
	public boolean hasFinishedLevel(Level l){
		return (Math.abs(getPosition().x - l.getEnd().x)<DEFAULT_RADIUS && Math.abs(getPosition().y - l.getEnd().y)<DEFAULT_RADIUS);
	}
	
	/**
	 * 
	 * @return the bonus possesed by the player
	 */
	public Bonus getBonus(){
		return bonus;
	}
	
	/**
	 * 
	 * @param b Bonus to check
	 * @return true if the player is close enough to obtain the bonus
	 */
	public boolean canTakeBonus(Bonus b){
		return (Math.abs(b.getPosition().x - getPosition().x)<35 && Math.abs(b.getPosition().y-getPosition().y)<35);
	}

	/**
	 * 
	 * @param d life to remove to the player's life
	 */
	public void damage(float d){
		this.life -= d;
	}
	
	/**
	 * Moves the player in jbox2d if needed
	 */
	public void move(ArrayList<Bonus> bonusList){
		if ( !isDead() ){
			KeyboardEvent k = keylist.poll();
			if ( k != null ){
				if ( config.validKey(k.getKey()) ){
					String direction = config.getDirection(k.getKey());
					float xForce;
					float yForce;
					switch (direction){
						case "up":
							xForce =(float) (2000*Math.cos(Math.toRadians(angle)));
							yForce =(float) (2000*Math.sin(Math.toRadians(angle)));
							corps.applyForce(new Vec2(xForce, yForce), corps.getPosition());
							break;
						
						case "down":
							if ( bonus != null ) {
								bonus.useBonus(w,this);
								bonus=null;
							}
							break;
						
						case "right":
							angle = (angle+DEFAULT_ANGLE)%360;
							break;
						
						case "left":
							angle = (angle-DEFAULT_ANGLE)%360;
							break;
							
					}
				}
			}
			/*
			 * Test if we are not on a Bonus to add it to the list
			 */
			for ( Bonus bb : bonusList ){
				if ( canTakeBonus(bb) ){
					bonus=bb;
				}
			}
		}
	}

}
